package com.lcl.stock.service.impl;

import com.alibaba.excel.EasyExcel;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lcl.stock.mapper.StockBlockRtInfoMapper;
import com.lcl.stock.mapper.StockMarketIndexInfoMapper;
import com.lcl.stock.mapper.StockRtInfoMapper;
import com.lcl.stock.pojo.domain.*;
import com.lcl.stock.pojo.vo.StockInfoConfig;
import com.lcl.stock.service.StockService;
import com.lcl.stock.utils.DateTimeUtil;
import com.lcl.stock.vo.resp.PageResult;
import com.lcl.stock.vo.resp.R;
import com.lcl.stock.vo.resp.ResponseCode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName StockServiceImpl
 * @Description TODO：股票实现类接口
 * @Author 28901
 * @Date 2025/2/25 8:40
 * @Version 1.0
 */

@Api(tags = "TODO：股票实现类接口")
@Service("stockService")
@Slf4j
public class StockServiceImpl implements StockService {

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;


    @Override
    public R<List<InnerMarketDomain>> getInnerMarketInfo() {
        //1.获取股票最新的交易时间点（精确到分钟，后面只为00
        DateTime lastTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date currentTime = lastTime.toDate();
        //mock data 等后续完成股票采集job工程
        currentTime = DateTime.parse("2021-12-28 09:31:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //2.获取大盘编码集合
        List<String> mCodes = stockInfoConfig.getInner();
        //3.调用mapper查询数据
        List<InnerMarketDomain> data = stockMarketIndexInfoMapper.getMarketInfo(currentTime,mCodes);
        //4.响应
        return R.ok(data);

    }

    /**
     * 股票板块统计
     * @return
     */
    @Override
    public R<List<StockBlockDomain>> sectorAllLimit() {
        //获取股票最新交易时间点
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO mock数据,后续删除
        lastDate=DateTime.parse("2021-12-21 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //1.调用mapper接口获取数据
        List<StockBlockDomain> infos=stockBlockRtInfoMapper.sectorAllLimit(lastDate);
        //2.组装数据
        if (CollectionUtils.isEmpty(infos)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA.getMessage());
        }
        return R.ok(infos);
    }
    /**
     * 分页查询最新的股票交易数据
     * @param page 当前页
     * @param pageSize 每页大小
     * @return
     */
    @Override
    public R<PageResult<StockUpdownDomain>> getStockInfoByPage(Integer page, Integer pageSize) {
        //1 获取股票最新交易时间点
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO mock数据,后续删除
        lastDate=DateTime.parse("2021-12-30 09:42:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2. 设置pageHelper分页参数
        PageHelper.startPage(page,pageSize);
        //3.调用mapper查询
        List<StockUpdownDomain> pageData = stockRtInfoMapper.getStockInfoByTime(lastDate);
        //4.组装pageResult对象
        PageInfo<StockUpdownDomain> pageInfo = new PageInfo<>(pageData);
        PageResult<StockUpdownDomain> pageResult = new PageResult<>(pageInfo);
        //5.封装，响应数据
        return R.ok(pageResult);
    }

    /**
     * 统计最新股票交易日内每分钟的涨跌停的股票数量
     * @return
     */
    @Override
    public R<Map<String, List>> getStockUpDownCount() {
        //1.获取最新股票交易时间点（截止时间）
        DateTime lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //TODO mock数据,后续删除
        lastDate=DateTime.parse("2022-01-06 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date curTime = lastDate.toDate();
        //2.获取最新交易时间点对应的开盘时间点
        Date openDate = DateTimeUtil.getOpenDate(lastDate).toDate();
        //3.统计涨停数据
        List<Map> upList = stockRtInfoMapper.getStockUpDownCount(openDate,curTime,1);
        //4.统计跌停数据
        List<Map> downList = stockRtInfoMapper.getStockUpDownCount(openDate,curTime,0);
        //5.组装数据
        HashMap<String,List> info = new HashMap<>();
        info.put("upList",upList);
        info.put("downList",downList);
        //6.响应数据
        return R.ok(info);
    }

    /**
     * 将指定页的股票数据导出到excel表下
     * @param response
     * @param page  当前页
     * @param pageSize 每页大小
     */
    @Override
    public void stockExport(HttpServletResponse response, Integer page, Integer pageSize) {
        R<PageResult<StockUpdownDomain>> r = this.getStockInfoByPage(page,pageSize);
        List<StockUpdownDomain> rows = r.getData().getRows();
        //2.将数据导出到Excel中
        //这里使用swagger会导致各种问题，直接用浏览器或postman
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        try {
            //URLEncoder.encode可以防止乱码
            String fileName = URLEncoder.encode("股票信息表","UTF-8");
            response.setHeader("Content-disposition","attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(),StockUpdownDomain.class).sheet("股票涨幅信息").doWrite(rows);
        } catch (IOException e) {
            log.info("当前导出数据异常，当前页：{},每页大小：{},异常信息：{}，时间：{}",page,pageSize,e.getMessage(),DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
            //通知前端异常，稍后重试
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            R<Object> error = R.error(ResponseCode.ERROR);
            try {
                String jsonData = new ObjectMapper().writeValueAsString(error);
                response.getWriter().write(jsonData);
            } catch (IOException ex) {
                log.error("stockExport 响应信息失败，时间：{}",DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
            }

        }
    }

    /**
     * 统计大盘t日和t-1日每分钟交易量的统计
     * @return
     */
    @Override
    public R<Map<String, List>> getComparedStockTradeAmt() {
        //1.获取T日（最新股票交易日的日期范围）
        DateTime tEndDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //假数据
        tEndDateTime=DateTime.parse("2022-01-03 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));

        Date tEndDate = tEndDateTime.toDate();
        //开盘时间
        Date tStartDate = DateTimeUtil.getOpenDate(tEndDateTime).toDate();
        //2.获取T-1日的时间范围
        DateTime preTEndDateTime = DateTimeUtil.getPreviousTradingDay(tEndDateTime);
       //mock，假数据
        preTEndDateTime=DateTime.parse("2022-01-02 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));

        Date preTEndDate = preTEndDateTime.toDate();
        Date preTStartDate = DateTimeUtil.getPreviousTradingDay(preTEndDateTime).toDate();
        //3 调用mapper
        //3.1 统计T日
        List<Map> tData = stockMarketIndexInfoMapper.getSumAmtInfo(tStartDate,tEndDate,stockInfoConfig.getInner());
        //3.2 统计T-1日
        List<Map> preTData = stockMarketIndexInfoMapper.getSumAmtInfo(preTStartDate,preTEndDate,stockInfoConfig.getInner());
        //4 组装数据
        HashMap<String,List> info = new HashMap<>();
        info.put("amtList",tData);
        info.put("yesAmtList",preTData);
        //5.响应数据
        return R.ok(info);
    }

    /**
     * 统计最新交易时间点下股票（A股）在各个涨幅区间的数量
     * @return
     */
    @Override
    public R<Map<String, Object>> getIncreaseRangeInfo() {
        //1.获取最新股票交易时间点
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //TODO mock数据,后续删除
        curDateTime=DateTime.parse("2022-01-06 09:55:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date curDate = curDateTime.toDate();

        //2. 调用mapper
        List<Map> infos = stockRtInfoMapper.getIncreaseRangeInfoByDate(curDate);
        //获取有序的标题集合
        List<String> upDownRange = stockInfoConfig.getUpDownRange();
        //将顺序的涨幅区间内的每个元素转化成map对象即可
        //方式一：
        List<Map> allInfos = new ArrayList<>();
        for (String title : upDownRange){
            Map tem = null;
            for (Map info : infos){
                if (info.containsValue(title)){
                    tem = info;
                    break;
                }
            }
            if (tem == null){
                //不存在，则补齐
                tem = new HashMap<>();
                tem.put("count",0);
                tem.put("title",title);
            }
            allInfos.add(tem);
        }
//        //方式二：
//        List<Map> aallInfos = upDownRange.stream().map(title -> {
//            Optional<Map> result = infos.stream().filter(map -> map.containsValue(title)).findFirst();
//            if (result.isPresent()) {
//                return result.get();
//            } else {
//                HashMap<String, Object> tmp = new HashMap<>();
//                tmp.put("count", 0);
//                tmp.put("title", title);
//                return tmp;
//            }
//        }).collect(Collectors.toList());

        //3.组装数据
        HashMap<String, Object> data = new HashMap<>();
        data.put("time",curDateTime.toString("yyyy-MM-dd HH:mm:ss"));
//        data.put("infos",infos);
        data.put("infos",allInfos);
        //4.响应数据
        return R.ok(data);
    }

    /**
     * 获取指定股票T日的分时数据
     * @param stockCode 股票编码
     * @return
     */
    @Override
    public R<List<Stock4MinuteDomain>> getStockScreenTimeSharing(String stockCode) {
        //1.获取最新股票交易时间点: openDate, curDate
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        //TODO mock数据,后续删除
        curDateTime=DateTime.parse("2021-12-30 14:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date curDate = curDateTime.toDate();
        Date openDate = DateTimeUtil.getOpenDate(curDateTime).toDate();
        //2.查询
        List<Stock4MinuteDomain> lists = stockRtInfoMapper.getStock4MinuteInfo(openDate,curDate,stockCode);
        //3.返回
        return R.ok(lists);
    }

    /**
     * 统计指定股票的日K线数据
     * @param stockCode 股票编码
     * @return
     */
    @Override
    public R<List<Stock4EvrDayDomain>> getStockScreenDkLine(String stockCode) {
        // 1. 获取统计日K线数据的时间范围 ： （2个月)
        //1.1 获取截止时间
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        endDateTime = DateTime.parse("2022-01-06 14:25:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date endDate = endDateTime.toDate();
        //1.2 获取起始时间
        DateTime startDateTime = endDateTime.minusMonths(2);
        Date startDate = startDateTime.toDate();

        //2.调用mapper接口获取查询的集合信息-方案1
//        List<Stock4EvrDayDomain> dkLineData = stockRtInfoMapper.getStock4DkLine(startDate,endDate,stockCode);
        //方案2：先获取指定日期范围内的收盘时间点集合
        List<Date> closeDates = stockRtInfoMapper.getCloseDates(stockCode, startDate, endDate);
        //根据收盘时间获取日K数据
        List<Stock4EvrDayDomain> dkLineData = stockRtInfoMapper.getStockCreenDkLineData(stockCode, closeDates);
        //3.返回
        return R.ok(dkLineData);
    }

    /**
     * 统计沪深两市个股最新交易数据，并按涨幅降序排序查询前4条数据
     * @return
     */
    @Override
    public R<List<StockUpdownDomain>> getStockInfoIncrease() {
        //1.获取当前时间
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        curDateTime = DateTime.parse("2022-06-07 15:00:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        Date curDate = curDateTime.toDate();

        //2.调用mapper查询
        List<StockUpdownDomain> lists = stockRtInfoMapper.getStockInfoIncrease(curDate);
        //3.响应数据
        return R.ok(lists);
    }
}
